//
//  LigaturePlayVC.swift
//  Game
//
//  Created by woniu on 2025/9/9.
//

import UIKit
import SnapKit

class LigaturePlayVC: BaseVC {
    public var gameModel:GameModel!
    
    private var wordItemList: [WordItem] = []
    
    private let leftTable = UITableView(frame: .zero, style: .plain)
    private let rightTable = UITableView(frame: .zero, style: .plain)
    private var placedMap: [Int?] = []
    private var connectionLayers: [Int: CAShapeLayer] = [:]
    
    private var draggingSnapshot: UIView?
    private var draggingSourceIndexPath: IndexPath?
    private var draggingWordIndex: Int?
    private var originalSnapshotCenter: CGPoint = .zero
    
    private let resetBtn = UIButton(type: .system)
    private let checkBtn = UIButton(type: .system)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        
        setupTables()
        setupBottomButtons()
        wordItemList = gameModel.words
        placedMap = Array(repeating: nil, count: wordItemList.count)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        updateConnections()
    }
    
    private func getItemWH()->(width:CGFloat,height:CGFloat){
        let realCount = wordItemList.count
        //
        let count = realCount >= 8 ? 8 : 6
        let cellHeight:CGFloat = view.height / CGFloat(count)
        let tableViewW:CGFloat = cellHeight + 20//20是左右边距
        return (tableViewW,cellHeight)
    }
    
    private func setupTables() {
        leftTable.register(UITableViewCell.self, forCellReuseIdentifier: "ImageCell")
        leftTable.dataSource = self
        leftTable.delegate = self
        leftTable.backgroundColor = .clear
        leftTable.separatorStyle = .none
        view.insertSubview(leftTable, at: 0)
        leftTable.translatesAutoresizingMaskIntoConstraints = false
        
        rightTable.register(UITableViewCell.self, forCellReuseIdentifier: "WordCell")
        rightTable.dataSource = self
        rightTable.delegate = self
        rightTable.backgroundColor = .clear
        rightTable.separatorStyle = .none
        
        view.insertSubview(rightTable, at: 0)
        rightTable.translatesAutoresizingMaskIntoConstraints = false
        
        
        let tableViewW:CGFloat = getItemWH().width
        
        leftTable.snp.makeConstraints { make in
            make.bottom.left.equalToSuperview()
            make.top.equalTo(backButton.snp.bottom)
            make.width.equalTo(tableViewW)
        }
        rightTable.snp.makeConstraints { make in
            make.right.bottom.equalToSuperview()
            make.top.equalTo(leftTable.snp.top)
            make.width.equalTo(leftTable.snp.width)
        }
        
        leftTable.isScrollEnabled = true
        rightTable.isScrollEnabled = true
        
        let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
        pan.delegate = self
        rightTable.addGestureRecognizer(pan)
    }
    
    private func setupBottomButtons() {
        resetBtn.setTitle("Reset", for: .normal)
        resetBtn.setTitleColor(.white, for: .normal)
        resetBtn.backgroundColor = UIColor(white: 0.15, alpha: 1)
        resetBtn.layer.cornerRadius = 8
        resetBtn.addTarget(self, action: #selector(onResetTapped), for: .touchUpInside)
        view.addSubview(resetBtn)
        resetBtn.snp.makeConstraints { make in
            make.width.equalTo(120)
            make.height.equalTo(48)
            make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-20)
            make.centerX.equalToSuperview().offset(-60-30)
        }
        checkBtn.setTitle("Check", for: .normal)
        checkBtn.setTitleColor(.white, for: .normal)
        checkBtn.backgroundColor = UIColor.systemBlue
        checkBtn.layer.cornerRadius = 8
        checkBtn.addTarget(self, action: #selector(onCheckTapped), for: .touchUpInside)
        view.addSubview(checkBtn)
        checkBtn.snp.makeConstraints { make in
            make.width.equalTo(120)
            make.height.equalTo(48)
            make.top.equalTo(resetBtn.snp.top)
            make.left.equalTo(resetBtn.snp.right).offset(60)
        }
        
    }
    
    //重置
    @objc private func onResetTapped() {
        placedMap = Array(repeating: nil, count: wordItemList.count)
        wordItemList.shuffle()
        leftTable.reloadData()
        rightTable.reloadData()
        clearConnections()
    }
    
    //检查
    @objc private func onCheckTapped() {
        for (index, _) in placedMap.enumerated(){
            guard let cell = leftTable.cellForRow(at: IndexPath(row: index, section: 0)) else { return }
            if let imageCard = cell.contentView.subviews.first as? ImageCardView {
                imageCard.reloadCheck(index: index)
            }
        }
        for(index,linLayer) in connectionLayers{
            guard let cell = leftTable.cellForRow(at: IndexPath(row: index, section: 0)) else { return }
            if let imageCard = cell.contentView.subviews.first as? ImageCardView {
                let delay = TimeInterval(index) * 0.50
                DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
                    if let re = imageCard.getIsCorrect(){
                        if re == true{
                            UIView.animate(withDuration: 0.5, animations: {
                                linLayer.strokeColor = Colors.green.cgColor
                            })
                            
                        }else{
                            UIView.animate(withDuration: 0.5, animations: {
                                linLayer.strokeColor = Colors.red.cgColor
                            })
                            
                        }
                    }
                }
                
            }
        }
    }
    
    // MARK: - Connections (lines)
    private func clearConnections() {
        for layer in connectionLayers.values { layer.removeFromSuperlayer() }
        connectionLayers.removeAll()
    }
    
    private func pointForLeftCard(at index: Int) -> CGPoint? {
        guard let cell = leftTable.cellForRow(at: IndexPath(row: index, section: 0)) else { return nil }
        let cardView = cell.contentView.subviews.first
        guard let cv = cardView else { return nil }
        let centerInCard = CGPoint(x: cv.bounds.midX, y: cv.bounds.midY)
        let cardCenter = cv.convert(centerInCard, to: view)
        return cardCenter
    }
    
    private func pointForRightCard(at index: Int) -> CGPoint? {
        guard let cell = rightTable.cellForRow(at: IndexPath(row: index, section: 0)) else { return nil }
        let cardView = cell.contentView.subviews.first
        guard let cv = cardView else { return nil }
        let centerInCard = CGPoint(x: cv.bounds.midX, y: cv.bounds.midY)
        let cardCenter = cv.convert(centerInCard, to: view)
        return cardCenter
    }
    
    private func drawConnection(from rightIndex: Int, to leftIndex: Int) {
        // compute rects in view coordinates for precise edge-to-edge connection
        guard let rCell = rightTable.cellForRow(at: IndexPath(row: rightIndex, section: 0)), let lCell = leftTable.cellForRow(at: IndexPath(row: leftIndex, section: 0)) else { return }
        guard let rView = rCell.contentView.subviews.first, let lView = lCell.contentView.subviews.first else { return }
        let rRect = rView.convert(rView.bounds, to: view)
        let lRect = lView.convert(lView.bounds, to: view)
        let start = edgePoint(on: rRect, toward: CGPoint(x: lRect.midX, y: lRect.midY))
        let end = edgePoint(on: lRect, toward: CGPoint(x: rRect.midX, y: rRect.midY))
        
        // remove existing for this leftIndex
        if let existing = connectionLayers[leftIndex] { existing.removeFromSuperlayer(); connectionLayers.removeValue(forKey: leftIndex) }
        
        let path = UIBezierPath()
        path.move(to: start)
        path.addLine(to: end)
        
        let shape = CAShapeLayer()
        shape.path = path.cgPath
        shape.strokeColor = UIColor.white.cgColor
        shape.lineWidth = 2.0
        shape.fillColor = UIColor.clear.cgColor
        shape.lineJoin = .round
        view.layer.addSublayer(shape)
        connectionLayers[leftIndex] = shape
    }
    
    private func updateConnections() {
        for (leftIndex, layer) in connectionLayers {
            if let rightIndex = placedMap[leftIndex] {
                guard let rCell = rightTable.cellForRow(at: IndexPath(row: rightIndex, section: 0)), let lCell = leftTable.cellForRow(at: IndexPath(row: leftIndex, section: 0)) else { continue }
                guard let rView = rCell.contentView.subviews.first, let lView = lCell.contentView.subviews.first else { continue }
                let rRect = rView.convert(rView.bounds, to: view)
                let lRect = lView.convert(lView.bounds, to: view)
                let start = edgePoint(on: rRect, toward: CGPoint(x: lRect.midX, y: lRect.midY))
                let end = edgePoint(on: lRect, toward: CGPoint(x: rRect.midX, y: rRect.midY))
                let path = UIBezierPath()
                path.move(to: start)
                path.addLine(to: end)
                layer.path = path.cgPath
            }
        }
    }
    
    // compute the intersection point on rect boundary in direction toward target (closest edge point)
    private func edgePoint(on rect: CGRect, toward target: CGPoint) -> CGPoint {
        let cx = rect.midX
        let cy = rect.midY
        let dx = target.x - cx
        let dy = target.y - cy
        if abs(dx) < 0.0001 && abs(dy) < 0.0001 {
            return CGPoint(x: cx, y: cy)
        }
        
        var candidates: [CGPoint] = []
        // vertical sides intersections
        if abs(dx) > 0.0001 {
            let tx1 = (rect.minX - cx) / dx
            let p1 = CGPoint(x: cx + tx1 * dx, y: cy + tx1 * dy)
            if p1.y >= rect.minY - 0.1 && p1.y <= rect.maxY + 0.1 { candidates.append(p1) }
            let tx2 = (rect.maxX - cx) / dx
            let p2 = CGPoint(x: cx + tx2 * dx, y: cy + tx2 * dy)
            if p2.y >= rect.minY - 0.1 && p2.y <= rect.maxY + 0.1 { candidates.append(p2) }
        }
        // horizontal sides intersections
        if abs(dy) > 0.0001 {
            let ty1 = (rect.minY - cy) / dy
            let q1 = CGPoint(x: cx + ty1 * dx, y: cy + ty1 * dy)
            if q1.x >= rect.minX - 0.1 && q1.x <= rect.maxX + 0.1 { candidates.append(q1) }
            let ty2 = (rect.maxY - cy) / dy
            let q2 = CGPoint(x: cx + ty2 * dx, y: cy + ty2 * dy)
            if q2.x >= rect.minX - 0.1 && q2.x <= rect.maxX + 0.1 { candidates.append(q2) }
        }
        
        if candidates.isEmpty {
            // fallback: nearest edge point
            let clampedX = min(max(target.x, rect.minX), rect.maxX)
            let clampedY = min(max(target.y, rect.minY), rect.maxY)
            let leftDist = abs(clampedX - rect.minX)
            let rightDist = abs(rect.maxX - clampedX)
            let topDist = abs(clampedY - rect.minY)
            let bottomDist = abs(rect.maxY - clampedY)
            let minDist = min(min(leftDist, rightDist), min(topDist, bottomDist))
            if minDist == leftDist { return CGPoint(x: rect.minX, y: clampedY) }
            if minDist == rightDist { return CGPoint(x: rect.maxX, y: clampedY) }
            if minDist == topDist { return CGPoint(x: clampedX, y: rect.minY) }
            return CGPoint(x: clampedX, y: rect.maxY)
        }
        
        var best = candidates[0]
        var bestDist = hypot(best.x - target.x, best.y - target.y)
        for c in candidates.dropFirst() {
            let d = hypot(c.x - target.x, c.y - target.y)
            if d < bestDist { best = c; bestDist = d }
        }
        return best
    }
    
    // MARK: - Drag
    @objc private func handlePan(_ g: UIPanGestureRecognizer) {
        
        switch g.state {
        case .began:
            guard let idxPath = rightTable.indexPathForRow(at: g.location(in: rightTable)) else { return }
            guard let cell = rightTable.cellForRow(at: idxPath) else { return }
            draggingSourceIndexPath = idxPath
            draggingWordIndex = idxPath.row
            let snapshot = snapshotOfCell(cell)
            snapshot.center = cell.convert(cell.contentView.center, to: view.window)
            view.window?.addSubview(snapshot)
            draggingSnapshot = snapshot
            originalSnapshotCenter = snapshot.center
            snapshot.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
            snapshot.alpha = 0.98
        case .changed:
            guard let snapshot = draggingSnapshot else { return }
            let translation = g.translation(in: view.window)
            snapshot.center = CGPoint(x: snapshot.center.x + translation.x, y: snapshot.center.y + translation.y)
            g.setTranslation(.zero, in: view.window)
            detectHighlightForSnapshot(snapshot)
        case .ended, .cancelled, .failed:
            guard let snapshot = draggingSnapshot, let wordIndex = draggingWordIndex else { cleanupDrag(); return }
            if let targetIndex = indexOfImageCellContaining(point: snapshot.center) {
                placedMap[targetIndex] = wordIndex
                if let cell = leftTable.cellForRow(at: IndexPath(row: targetIndex, section: 0)), let imageCard = cell.contentView.subviews.first as? ImageCardView {
                    imageCard.onSelectedItem(wordItemList[wordIndex])
                    imageCard.setHighlighted(false)
                }
                // draw a connecting line between the right card (wordIndex) and left card (targetIndex)
                drawConnection(from: wordIndex, to: targetIndex)
                UIView.animate(withDuration: 0.3, animations: {
                    snapshot.alpha = 0.0
                    snapshot.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
                }, completion: { _ in snapshot.removeFromSuperview() })
            } else {
                UIView.animate(withDuration: 0.36, animations: {
                    snapshot.center = self.originalSnapshotCenter
                    snapshot.transform = .identity
                }, completion: { _ in snapshot.removeFromSuperview() })
            }
            cleanupDrag()
        default:
            break
        }
    }
    
    private func cleanupDrag() {
        for i in 0..<wordItemList.count {
            if let cell = leftTable.cellForRow(at: IndexPath(row: i, section: 0)), let imageCard = cell.contentView.subviews.first as? ImageCardView {
                imageCard.setHighlighted(false)
            }
        }
        draggingSnapshot?.removeFromSuperview()
        draggingSnapshot = nil
        draggingSourceIndexPath = nil
        draggingWordIndex = nil
    }
    
    private func snapshotOfCell(_ cell: UITableViewCell) -> UIView {
        let snapshotFrame = CGRect(x: 10, y: 10, width: cell.contentView.width-20, height: cell.contentView.height-20)
        let snapshot = UIView(frame: snapshotFrame)
        snapshot.backgroundColor = UIColor(white: 0.18, alpha: 1)
        snapshot.layer.cornerRadius = 10
        snapshot.layer.shadowColor = UIColor.black.cgColor
        snapshot.layer.shadowOpacity = 0.25
        snapshot.layer.shadowRadius = 6
        snapshot.layer.shadowOffset = CGSize(width: 0, height: 3)
        let label = UILabel(frame: CGRect(x: 12, y: 8, width: snapshot.bounds.width - 24, height: snapshot.bounds.height - 16))
        label.textAlignment = .center
        if let contentLabel = cell.contentView.subviews.first(where: { $0 is WordCardView }) as? WordCardView {
            label.text = contentLabel.label.text
        } else if let wordCellLabel = cell.textLabel {
            label.text = wordCellLabel.text
        }
        label.font = UIFont.systemFont(ofSize: 30, weight: .bold)
        label.textColor = .white
        snapshot.addSubview(label)
        return snapshot
    }
    
    private func detectHighlightForSnapshot(_ snapshot: UIView) {
        let center = snapshot.center
        var highlightedAny = false
        for i in 0..<wordItemList.count {
            let idx = IndexPath(row: i, section: 0)
            if let cell = leftTable.cellForRow(at: idx), let imageCard = cell.contentView.subviews.first as? ImageCardView {
                let cellFrameInWindow = cell.convert(cell.bounds, to: view.window)
                if cellFrameInWindow.contains(center) {
                    imageCard.setHighlighted(true)
                    highlightedAny = true
                } else {
                    imageCard.setHighlighted(false)
                }
            }
        }
        if !highlightedAny { }
    }
    
    private func indexOfImageCellContaining(point: CGPoint) -> Int? {
        for i in 0..<wordItemList.count {
            let idx = IndexPath(row: i, section: 0)
            if let cell = leftTable.cellForRow(at: idx) {
                let cellFrameInWindow = cell.convert(cell.bounds, to: view.window)
                if cellFrameInWindow.contains(point) { return i }
            }
        }
        return nil
    }
}

extension LigaturePlayVC: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true }
}

// update connections when tables scroll
extension LigaturePlayVC: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        updateConnections()
    }
}

extension LigaturePlayVC: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return wordItemList.count }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        
        let cellHeight:CGFloat = getItemWH().height
        return cellHeight
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if tableView == leftTable {
            let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell", for: indexPath)
            cell.backgroundColor = .clear
            cell.selectionStyle = .none
            cell.contentView.subviews.forEach { $0.removeFromSuperview() }
            let card = ImageCardView(frame: .zero)
            let item = wordItemList[indexPath.row]
            card.update(item: item)
            if let img = GameManager.share.getImageBy(item.imgName) {
                card.imageView.image = img
            } else {
                card.imageView.backgroundColor = UIColor(white: 0.2, alpha: 1)
            }
            if let placed = placedMap[indexPath.row] {
                card.onSelectedItem(wordItemList[placed])
            } else {
                card.onSelectedItem(nil)
            }
            cell.contentView.addSubview(card)
            card.snp.remakeConstraints { make in
                make.top.equalToSuperview().offset(10)
                make.bottom.equalToSuperview().offset(-10)
                make.left.equalToSuperview().offset(10)
                make.right.equalToSuperview().offset(-10)
                //                make.edges.equalToSuperview()
            }
            return cell
            
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "WordCell", for: indexPath)
            cell.backgroundColor = .clear
            cell.selectionStyle = .none
            cell.contentView.subviews.forEach { $0.removeFromSuperview() }
            let card = WordCardView(frame: .zero)
            card.label.text = wordItemList[indexPath.row].word
            cell.contentView.addSubview(card)
            card.snp.remakeConstraints { make in
                make.top.equalToSuperview().offset(10)
                make.bottom.equalToSuperview().offset(-10)
                make.left.equalToSuperview().offset(10)
                make.right.equalToSuperview().offset(-10)
            }
            return cell
        }
    }
}

